////////////////////////////////////////////////////////////////////////////////
//	Copyright (c) 2004 by Michael 'Astar' Sotnikov
//	stari4ek at gmail dot com
////////////////////////////////////////////////////////////////////////////////

#include "cModules.hpp"

#include "cSmartAssert.hpp"

#include <set>
#include <string>

//////////////////////////////////////////////////////////////////////////
Module_c::Module_c()
:	m_active( false )
{
}

Module_c::~Module_c()
{
}

bool Module_c::ModuleInit()
{
	SMART_ASSERT( !m_active )
		.error( "Module already active." );

	m_active = true;
	return true;
}

bool Module_c::ModuleDone()
{
	SMART_ASSERT( m_active )
		.error( "Module was not active." );

	m_active = false;
	return true;
}

bool Module_c::IsActive() const
{
	return m_active;
}


////////////////////////////////////////////////////////////////////////////////
ModuleRegister_c::ModuleRegister_c()
{
}

void ModuleRegister_c::Activate( const std::string& name )
{
	SMART_ASSERT( IsRegistered( name ) )
		( name )
		.error( "Can't find module. Did you register it?" );

	if( IsRegistered( name ) )
	{
		// if it isn't active yet
		if( !IsActive( name ) )
		{
			// prevent from infinite loop
			// WARN: thread safity. we can't use static object here, if we
			// have more than 1 object. While we use ModuleRegister_c like 
			// SINGLETON everything is fine.
			static std::set<std::string> activating_modules;
			if( activating_modules.insert( name ).second )
			{
				// activate needed modules
				const char* *prereqs = m_creators[name]().ModuleDependsOn();
				while( *prereqs )
				{
					Activate( std::string( *prereqs ) );
					++prereqs;
				}

				activating_modules.erase( name );

				SMART_VERIFY( m_creators[name]().ModuleInit() )
					( name )
					.warn( "Module's activation failed." );
			}
			else
			{
				SMART_FAILED()
					( name )( activating_modules )
					.error( "Looped dependences for module." );
			}
		}
		else
		{
			SMART_FAILED()
				( name )
				.warn( "Module is already active." );
		}
	}
}

bool ModuleRegister_c::IsRegistered( const std::string& name ) const
{
	return ( m_creators.find( name ) != m_creators.end() );
}

bool ModuleRegister_c::IsActive( const std::string& name ) const
{
	if( IsRegistered( name ) )
	{
		Creators_t::const_iterator it = m_creators.find( name );
		if( it != m_creators.end() )
			return it->second().IsActive();
	}

	return false;
}
